`timescale 1ns / 1ps
/************************************************************\
 **  Copyright (c) 2022-2023 Gonsin, Inc.
 **  All Right Reserved.
 **  Author: JunZeng
 **  Description: temac_loop
 **  Rev 1.0
\************************************************************/

module temac_loop (
// 异步复位
input resetN_i,

// 时钟
input wire clk25M_i,

// RGMII 接口
output [3:0] rgmii4b_txd_o,
output rgmii_txCtl_o,
output rgmii_txc_o,
input [3:0] rgmii4b_rxd_i,
input rgmii_rxCtl_i,
input rgmii_rxc_i,

// MDIO 接口
inout mdio_io,
output mdc_o
);

//----------------------------------------------------------------------------
// top level parameter
//----------------------------------------------------------------------------	
//----------------------------------------------------------------   
//IP核生成时，GUI配置的参数
//----------------------------------------------------------------
parameter P_HALF_DUPLEX = 1'b1;		// 如果为true，则内核半双工和全双工模式，否则仅支持全双工模式。
parameter P_HOST_EN = 1'b0;		    // 如果为true，则内核仅支持AXI接口管理配置，否则内核仅支持矢量总线配置。
parameter P_ADD_FILT_EN = 1'b1;   // 如果为true，则内核支持地址过滤。
parameter P_ADD_FILT_LIST	= 16;		// 内核支持的地址表可配置地址个数
parameter P_SPEED_10_100 = 1'b0;	// 如果为true，则内核仅支持10/100 Mbps速度。
parameter P_SPEED_1000 = 1'b0;		// 如果为true，则内核仅支持1000 Mbps速度。
parameter P_TRI_SPEED = 1'b1;		  // 如果为true，则内核支持3速

//----------------------------------------------------------------   
// MAC核配置参数
//----------------------------------------------------------------
parameter TX_CFG	= {24'b0,1'b0,7'b0101010};    //发送器配置
parameter RX_CFG	= {24'b0,8'b00101010};        //接收器配置 
parameter PAUSE_SRCAD_CFG = 48'hf6f5f4f3f25a;   //暂停帧mac源地址配置
parameter SPEED_CFG = {30'b0,2'b10};            //速度配置 2'b10 千兆 2'b01 百兆(default) 2'b00十兆
parameter FLOW_CTRL_CFG = {30'b0,2'b00};        //流控配置 
parameter AD_FILTER_MODE_CFG	= {31'b0,1'b0};   //地址过滤模式配置：1'b1：启用混杂模式  1'b0：启用地址过滤模式
parameter UNICAST_AD_CFG	= 48'h0605040302DA;   //单播地址配置
parameter AD_TABLE0_CFG = 48'h0605040302AB;     //地址表地址配置 48'h06050403020A
parameter AD_TABLE1_CFG = 48'h16151413121A;
parameter AD_TABLE2_CFG = 48'h26252423222A;
parameter AD_TABLE3_CFG = 48'h36353433323A;
parameter AD_TABLE4_CFG = 48'h46454443424A;
parameter AD_TABLE5_CFG = 48'h56555453525A;
parameter AD_TABLE6_CFG = 48'h66656463626A;
parameter AD_TABLE7_CFG = 48'h76757473727A;
parameter AD_TABLE8_CFG = 48'h86858483828A;
parameter AD_TABLE9_CFG = 48'h96959493929A;
parameter AD_TABLE10_CFG = 48'hA6A5A4A3A2AA;
parameter AD_TABLE11_CFG = 48'hB6B5B4B3B2BA;
parameter AD_TABLE12_CFG = 48'hC6C5C4C3C2CA;
parameter AD_TABLE13_CFG = 48'hD6D5D4D3D2DA;
parameter AD_TABLE14_CFG = 48'hE6E5E4E3E2EA;
parameter AD_TABLE15_CFG = 48'hF6F5F4F3F2FA;
parameter MDIO_CLK_CFG = {25'b0,7'b1001001};      //mdc配置： mdc = m_axi_aclk/(9+1)*2=50/20=2.5MHZ
parameter MDIO_WE1_DATA_CFG	= {16'h0,16'h9340};   //16'h9340(千兆全双工);16'hb300(百兆全双工);16'h9300(十兆全双工);16'h9240(千兆半双工、核不支持);16'hb200(百兆半双工);16'h9200(十兆半双工) 
parameter MDIO_WE1_CTRL_CFG	= {19'b0,5'b00000,5'b00001,2'b01,1'b1};   //PHY芯片地址：phy_A:5'b00010  phy_B:5'b00001   对PHY仅配置基本模式控制寄存器（0x00/5'h00）即可:双工/速度配置  
parameter MDIO_RD1_CTRL_CFG	= {19'b0,5'b00000,5'b00001,2'b10,1'b1};   //读取对PHY芯片配置值

//----------------------------------------------------------------------------
// 模块内部信号
//----------------------------------------------------------------------------

//时钟信号
wire gtx_clk_w;       // 125MHz

wire sAXI_aclk_w;     // 50MHz
//wire sAXI_aclkBufg_w;

// mac核时钟信号 / 时钟使能信号
wire tx_clkInt_w;
wire rx_clkInt_w;                     
wire rx_clkEnInt_w;                
wire tx_clkEnInt_w;

//复位信号
wire tx_reset_w;  

// Tx LocalLink FIFO I/F
reg [5:0] tx6b_LLpreReset;
reg tx_LLreset;

wire tx_LLclk_w;
wire [7:0] tx8b_LLdata_w;
wire tx_LLsofN_w;
wire tx_LLeofN_w;
wire tx_LLsrc_rdyN_w;
wire tx_LLdst_rdyN_w;

// Rx LocalLink FIFO I/F
wire rx_LLreset_w;

wire rx_LLclk_w;
wire [7:0] rx8b_LLdata_w;
wire rx_LLsofN_w;
wire rx_LLeofN_w;
wire rx_LLsrc_rdyN_w;
wire rx_LLdst_rdyN_w;

// Tx和Rx统计状态向量
wire [26:0] rx27b_statusVector_int_w;
wire rx_statusVld_int_w;
wire [28:0] tx29b_statusVector_int_w;
wire tx_statusVld_int_w;

// 客户端接口
wire tx_rdy_w;
wire tx_stop_w;
wire [7:0] tx8b_ifgVal_w;

// 流控接口
wire pause_req_w;
wire [15:0] pause16b_val_w;
wire [47:0] pause48b_sourceAddr_w;

// 初始默认单播地址值  
wire [47:0] unicast48b_address_w;

// 向量配置总线 
wire [19:0] mac20b_cfgVector_w;  
      
// AXI总线
wire [7:0] sAXI8b_awaddr_w;    
wire sAXI_awvalid_w;    
wire sAXI_awready_w;    
wire [31:0] sAXI32b_wdata_w;       
wire sAXI_wvalid_w;    
wire sAXI_wready_w;    
wire [1:0] sAXI2b_bresp_w;    
wire sAXI_bvalid_w;    
wire sAXI_bready_w;    
wire [7:0] sAXI8b_araddr_w;      
wire sAXI_arvalid_w;    
wire sAXI_arready_w;    
wire [31:0] sAXI32b_rdata_w;    
wire [1:0] sAXI2b_rresp_w;    
wire sAXI_rvalid_w;    
wire sAXI_rready_w;
 
// MDIO接口
reg mdio;
wire mdio_w;
wire mdio_oen_w;

//============================================================          
//  mdio port
//============================================================
assign mdio_io = mdio_oen_w ? 1'bz : mdio_w;

//assign mdio = mdio_io;
always@(mdio_io) begin
  mdio = mdio_io;
end
            
//============================================================
// pllclk
//============================================================  
wire resetn;
	
pllclk pllclk_u
(
.refclk(clk25M_i),
.reset(~resetN_i),
.extlock(resetn),
.clk0_out(gtx_clk_w),     //C0 | 125.000000MHZ	| 0  DEG     
.clk1_out(sAXI_aclk_w)    //C1 | 50.000000 MHZ	| 0  DEG 
);

assign  reset = !resetn;
  
//=============================================================================================
// 参数配置逻辑
//=============================================================================================
//需配置的客户端接口（初始默认值）

assign tx_stop_w = 1'b0;
assign tx8b_ifgVal_w = 8'h00;

assign pause_req_w = 1'b0;
assign pause16b_val_w = 16'h0;
assign pause48b_sourceAddr_w = 48'h5af1f2f3f4f5;

assign unicast48b_address_w = UNICAST_AD_CFG;
assign mac20b_cfgVector_w = {1'b0,2'b00,2'b10,8'b00000010,7'b0000010};   //使能矢量配置时（P_HOST_EN = 1'b0），由mac_cfg_vector给内核配置，此时AXI管理接口无效

//------------------------------------------------------------------------
//每次复位后，基于AXI_Master模块流水线配置mac内核和PHY芯片 
wire init_axi_txn;
wire axi_txn_done;
reg init_axi_txn_reg;   /*synthesis keep=true*/
reg	reset_ff,reset_ff2;

always@(posedge sAXI_aclk_w) begin                                                                            
  reset_ff <= reset;
  reset_ff2 <= reset_ff;                                                                                                                                       
end 
    
always@(posedge sAXI_aclk_w) begin                                                                           
  if (reset == 1)                                                                                                                     
    init_axi_txn_reg <= 1'b0;                                                                                                                               
  else if((!reset_ff) && reset_ff2)     //下降沿                                                                 
    init_axi_txn_reg <= 1'b1;  
  else if(axi_txn_done)                                                                      
    init_axi_txn_reg <= 1'b0;    
end 
  
assign  init_axi_txn = init_axi_txn_reg;   // (initiate)发起AXI事务，在 reset下降沿

axi_master_cfg #(
.TX_CFG(TX_CFG),
.RX_CFG(RX_CFG),
.PAUSE_SRCAD_CFG(PAUSE_SRCAD_CFG),
.SPEED_CFG(SPEED_CFG),
.FLOW_CTRL_CFG(FLOW_CTRL_CFG),
.AD_FILTER_MODE_CFG(AD_FILTER_MODE_CFG),
.UNICAST_AD_CFG(UNICAST_AD_CFG),
.AD_TABLE0_CFG(AD_TABLE0_CFG),
.AD_TABLE1_CFG(AD_TABLE1_CFG),
.AD_TABLE2_CFG(AD_TABLE2_CFG),
.AD_TABLE3_CFG(AD_TABLE3_CFG),
.AD_TABLE4_CFG(AD_TABLE4_CFG),
.AD_TABLE5_CFG(AD_TABLE5_CFG),
.AD_TABLE6_CFG(AD_TABLE6_CFG),
.AD_TABLE7_CFG(AD_TABLE7_CFG),
.AD_TABLE8_CFG(AD_TABLE8_CFG),
.AD_TABLE9_CFG(AD_TABLE9_CFG),
.AD_TABLE10_CFG(AD_TABLE10_CFG),
.AD_TABLE11_CFG(AD_TABLE11_CFG),
.AD_TABLE12_CFG(AD_TABLE12_CFG),
.AD_TABLE13_CFG(AD_TABLE13_CFG),
.AD_TABLE14_CFG(AD_TABLE14_CFG),
.AD_TABLE15_CFG(AD_TABLE15_CFG),
.MDIO_CLK_CFG(MDIO_CLK_CFG),
.MDIO_WE1_DATA_CFG(MDIO_WE1_DATA_CFG),
.MDIO_WE1_CTRL_CFG(MDIO_WE1_CTRL_CFG),
.MDIO_RD1_CTRL_CFG(MDIO_RD1_CTRL_CFG)
) axi_master_cfg_u (	
.init_AXItxn_i(init_axi_txn),   // (initiate)发起AXI事务
.mAXI_txnDone_o(axi_txn_done),  // AXI事务完成时置高
//AXI总线         
.mAXI_aclk_i(sAXI_aclk_w),
.mAXI_areset_i(reset),
.mAXI8b_awaddr_o(sAXI8b_awaddr_w),
.mAXI_awvalid_o(sAXI_awvalid_w),
.mAXI_awready_i(sAXI_awready_w),
.mAXI32b_wdata_o(sAXI32b_wdata_w),   
.mAXI_wvalid_o(sAXI_wvalid_w),
.mAXI_wready_i(sAXI_wready_w),
.mAXI2b_bresp_i(sAXI2b_bresp_w),
.mAXI_bvalid_i(sAXI_bvalid_w),
.mAXI_bready_o(sAXI_bready_w),
.mAXI8b_araddr_o(sAXI8b_araddr_w),
.mAXI_arvalid_o(sAXI_arvalid_w),
.mAXI_arready_i(sAXI_arready_w),
.mAXI32b_rdata_i(sAXI32b_rdata_w),
.mAXI2b_rresp_i(sAXI2b_rresp_w),
.mAXI_rvalid_i(sAXI_rvalid_w),
.mAXI_rready_o(sAXI_rready_w) 
);  
 
//===========================================================================================
// ODDR、BUFG、reset_sync等逻辑
//===========================================================================================

//------------------------------------------------------------------------
// Drive client clocks off chip
/* 
oddr rx_clk_ddr(
.q(rx_clk),
.clk(rx_clkInt_w),
.d1(1'b0),
.d0(1'b1),
.rst(reset)
);

oddr tx_clk_ddr(
.q(tx_clk),
.clk(tx_clkInt_w),
.d1(1'b0),
.d0(1'b1),
.rst(reset)
);
*/ 

//----------------------------------------------------------------------------
// 产生用于 client_loopback模块 和 FIFO 的 时钟 和 同步复位信号
//----------------------------------------------------------------------------

// 在Tx时钟域中生成同步复位信号
reset_sync tx_reset_gen (
.clk_i(tx_clkInt_w),
.enable_i(1'b1),
.reset_i(reset),
.reset_o(tx_reset_w)
);

// 在 LocalLink 发送时钟域 中 生成 完全同步复位
always@(posedge tx_clkInt_w) begin
  if (tx_reset_w) begin
    tx6b_LLpreReset <= 6'b111111;
    tx_LLreset <= 1;
  end
  else begin
    tx6b_LLpreReset[0] <= 0;
    tx6b_LLpreReset[5:1] <= tx6b_LLpreReset[4:0];
    tx_LLreset <= tx6b_LLpreReset[5];
  end
end 

//----------------------------------
// LocalLink FIFO Clock and Reset 
assign tx_LLclk_w = tx_clkInt_w;
assign rx_LLclk_w = tx_clkInt_w;

assign rx_LLreset_w = tx_LLreset;

//----------------------------------------------------------------------------
//  例化 loopback 模块；   环回输出帧：目的地址和源地址交换
//----------------------------------------------------------------------------
client_loopback client_loopback_u (
.rx_LLclock_i(tx_clkInt_w),
.rx_LLreset_i(tx_LLreset),
.rx8b_LLdata_i(rx8b_LLdata_w),
.rx_LLsofN_i(rx_LLsofN_w),
.rx_LLeofN_i(rx_LLeofN_w),
.rx_LLsrc_rdyN_i(rx_LLsrc_rdyN_w),
.tx8b_LLdata_o(tx8b_LLdata_w),
.tx_LLsofN_o(tx_LLsofN_w),
.tx_LLeofN_o(tx_LLeofN_w),
.tx_LLsrc_rdyN_o(tx_LLsrc_rdyN_w),
.tx_LLdst_rdyN_i(tx_LLdst_rdyN_w)
);

assign rx_LLdst_rdyN_w = tx_LLdst_rdyN_w;
  
/*   
//----------------------------------------------------------------------------
// 数据生成模块：为了测试流控、IFG调整功能
//----------------------------------------------------------------------------
//data_gen_flow_ctrl u1_data_gen_flow_ctrl  //用于 接收器流控 功能测试
data_gen  u1_data_gen (         //用于 IFG调整 功能测试 或者 loopback功能测试
.rx_ll_clock(tx_clkInt_w),
.rx_LLreset_w(tx_LLreset),

.tx_gen_data_en(axi_txn_done),  // 配置完成后，开始发送产生的帧数据，使能信号高电平有效

.rx_ll_data_in(rx8b_LLdata_w),
.rx_ll_sof_in_n(rx_LLsofN_w),
.rx_ll_eof_in_n(rx_LLeofN_w),
.rx_ll_src_rdy_in_n(rx_LLsrc_rdyN_w),

.tx8b_LLdata_w(tx8b_LLdata_w),
.tx_ll_sof_out_n(tx_LLsofN_w),
.tx_ll_eof_out_n(tx_LLeofN_w),
.tx_ll_src_rdy_out_n(tx_LLsrc_rdyN_w),
.tx_ll_dst_rdy_in_n(tx_LLdst_rdyN_w)
);

assign rx_LLdst_rdyN_w = tx_LLdst_rdyN_w;
*/

//----------------------------------------------------------------------------
// 例化 TRIMAC locallink 模块
//----------------------------------------------------------------------------
temac_locallink #(
.P_ADD_FILT_EN(P_ADD_FILT_EN), 
.P_ADD_FILT_LIST(P_ADD_FILT_LIST),     
.P_HALF_DUPLEX(P_HALF_DUPLEX), 
.P_HOST_EN(P_HOST_EN),  
.P_SPEED_1000(P_SPEED_1000),
.P_SPEED_10_100(P_SPEED_10_100), 
.P_TRI_SPEED(P_TRI_SPEED)
) temac_locallink_u (
// 异步复位
.reset_i(reset),

//全局发送时钟
.gtx_clk_i(gtx_clk_w),

// 客户端接收接口
.rx_clk_o(rx_clkInt_w),
.rx_clkEn_o(rx_clkEnInt_w),
.rx27b_statusVector_o(rx27b_statusVector_int_w),
.rx_statusVld_o(rx_statusVld_int_w),

// 客户端接收（FIFO侧）接口
.rx_LLclock_i(rx_LLclk_w),
.rx_LLreset_i(rx_LLreset_w),
.rx8b_LLdata_o(rx8b_LLdata_w),
.rx_LLsof_outN_o(rx_LLsofN_w),
.rx_LLeof_outN_o(rx_LLeofN_w),
.rx_LLsrcRdy_outN_o(rx_LLsrc_rdyN_w),
.rx_LLdstRdy_inN_i(rx_LLdst_rdyN_w),

// 客户端发送器接口
.tx_clk_o(tx_clkInt_w),
.tx_clkEn_o(tx_clkEnInt_w),
.tx_rdy_o(tx_rdy_w),
.tx_stop_i(tx_stop_w),
.tx8b_ifgVal_i(tx8b_ifgVal_w),
.tx29b_statusVector_o(tx29b_statusVector_int_w),
.tx_statusVld_o(tx_statusVld_int_w),

// 客户端发送（FIFO侧）接口
.tx_LLclock_i(tx_LLclk_w),
.tx_LLreset_i(tx_LLreset),
.tx8b_LLdata_i(tx8b_LLdata_w),
.tx_LLsof_inN_i(tx_LLsofN_w),
.tx_LLeof_inN_i(tx_LLeofN_w),
.tx_LLsrcRdy_inN_i(tx_LLsrc_rdyN_w),
.tx_LLdstRdy_outN_o(tx_LLdst_rdyN_w),

// 流控接口
.pause_req_i(pause_req_w),
.pause16b_val_i(pause16b_val_w),
.pause48b_sourceAddr_i(pause48b_sourceAddr_w),

// 初始默认单播地址值
.unicast48b_address_i(unicast48b_address_w),

// AXI主机管理接口
.sAXI_aclk_i(sAXI_aclk_w), 
.sAXI8b_awaddr_i(sAXI8b_awaddr_w),    //input wire [7:0]     
.sAXI_awvalid_i(sAXI_awvalid_w),      //input wire             
.sAXI_awready_o(sAXI_awready_w),      //output wire             
.sAXI32b_wdata_i(sAXI32b_wdata_w),    //input wire [31:0]     
.sAXI_wvalid_i(sAXI_wvalid_w),        //input wire             
.sAXI_wready_o(sAXI_wready_w),        //output wire             
.sAXI2b_bresp_o(sAXI2b_bresp_w),      //output wire [1:0]     
.sAXI_bvalid_o(sAXI_bvalid_w),        //output wire             
.sAXI_bready_i(sAXI_bready_w),        //input wire             
.sAXI8b_araddr_i(sAXI8b_araddr_w),    //input wire [7:0]     
.sAXI_arvalid_i(sAXI_arvalid_w),      //input wire             
.sAXI_arready_o(sAXI_arready_w),      //output wire             
.sAXI32b_rdata_o(sAXI32b_rdata_w),    //output wire [31:0]     
.sAXI2b_rresp_o(sAXI2b_rresp_w),      //output wire [1:0]     
.sAXI_rvalid_o(sAXI_rvalid_w),        //output wire             
.sAXI_rready_i(sAXI_rready_w),        //input wire

// 向量配置总线
.mac20b_cfgVector_i(mac20b_cfgVector_w),

// RGMII 接口
.rgmii4b_txd_o(rgmii4b_txd_o),
.rgmii_txCtl_o(rgmii_txCtl_o),
.rgmii_txc_o(rgmii_txc_o),
.rgmii4b_rxd_i(rgmii4b_rxd_i),
.rgmii_rxCtl_i(rgmii_rxCtl_i),
.rgmii_rxc_i(rgmii_rxc_i),

// RGMII 状态寄存器
.inband_linkStatus_o(inband_link_status),
.inband2b_clockSpeed_o(inband_clock_speed),
.inband_duplexStatus_o(inband_duplex_status),

// MDIO 接口
.mdio_i(mdio),
.mdio_o(mdio_w),
.mdio_oen_o(mdio_oen_w),  
.mdio_clk_o(mdc_o)   
);

endmodule